package com.googlecode.chigscommons.repository.jpa.impl;

import java.util.List;

import javax.annotation.Resource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.security.authentication.dao.SaltSource;
import org.springframework.security.authentication.encoding.PasswordEncoder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.googlecode.chigscommons.domain.User;
import com.googlecode.chigscommons.repository.MailService;
import com.googlecode.chigscommons.repository.UserService;
import com.googlecode.chigscommons.repository.jpa.UserDao;

@Service(value="userService")
@Transactional
public class UserDetailsServiceImpl implements UserService, UserDetailsService {
	private final static Logger log = LoggerFactory.getLogger(UserDetailsServiceImpl.class);
	
	@Autowired
	private PasswordEncoder passwordEncoder;
	
	@Autowired
	private SaltSource saltSource;
	
	@Autowired
	private MailService mailService;

	@Resource
	private UserDao userDao;
	
    private static int randomInt(int min, int max) {
        return (int)(Math.random() * (max - min) + min);
    }
    
    private static String randomString(int min, int max) {
        int num = randomInt(min, max);
        byte b[] = new byte[num];
        for (int i = 0; i < num; i++) {
            b[i] = (byte)randomInt('a', 'z');
        }
        return new String(b);
    }

    public void initAdmin() {
		if (userDao.count().longValue() == 0) {
			User admin = new User();
			admin.setEmail("admin@localhost");
			admin.setPassword("admin");
			admin.setFirstname("auto");
			admin.setLastname("generated");
			admin.setAdmin(true);
			admin.setEnabled(true);
			saveUser(admin);
			log.info("auto generated admin user created. Login: admin@localhost / Password: admin");
		}
	}
	
	@Override
	public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException, DataAccessException {
		final User user = userDao.findByEmail(email);
		if (user == null) {
			throw new UsernameNotFoundException("no user for email: " + email);
		}
		return new UserServiceImpl(user);
	}

	@Override
	public User saveUser(User user) {
		if (user.isNew()) {
			user = userDao.save(user);
			user.setPassword(passwordEncoder.encodePassword(user.getPassword(), saltSource.getSalt(new UserServiceImpl(user))));
			user.setActivationKey(randomString(10, 12));
			log.info("creating new user: " + user);
		} else {
			final User u = userDao.findByEmail(user.getEmail());
			if (user.getPassword() == null || "".equals(user.getPassword())) {
				user.setPassword(u.getPassword());
				log.info("updating user: " + user);
			} else {
				user.setPassword(passwordEncoder.encodePassword(user.getPassword(), saltSource.getSalt(new UserServiceImpl(user))));
				log.info("updating user (new password): " + user);
			}
		}
		return userDao.save(user);
	}

	@Override
	public void deleteUser(User user) {
		userDao.delete(userDao.readByPrimaryKey(user.getId()));
	}
	
	@Override
	public void signupUser(User user) {
		User u = saveUser(user);

		if (!mailService.sendSignupMail(u)) {
			log.error("error sending activation mail. user will be enabled automatically.");
			u = userDao.findByEmail(u.getEmail());
			u.setEnabled(true);
			userDao.save(u);
		}
	}

	@Override
	public User loadUser(Long id) {
		return userDao.readByPrimaryKey(id);
	}

	@Override
	public List<User> loadAllUser() {
		return userDao.readAll();
	}
}
